/**
 * 
 */
package core.proto;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.swing.Box;
import javax.swing.DropMode;
import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.RowSorter;
import javax.swing.TransferHandler;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;

import org.apache.commons.lang.StringUtils;

import app.constants.CollabVizConstants;
import app.exceptions.CollabVizException;
import app.service.xml.XMLService;
import app.util.PropertyLoaderUtil;
import app.xml.model.AnnotationTag;
import app.xml.model.DateTag;
import app.xml.model.FileHistoryTag;
import app.xml.model.FileTag;
import app.xml.model.NoteTag;
import core.util.logging.SimpleLogger;
import core.util.logging.constants.Location;

// import com.eteks.jeks.JeksTable;

/**
 * @author poornima
 * 
 */
public class HistoryRenderer {
	// default number of rows
	private int ROWS = 1;
	// default number of columns
	private int COLS = 5;
	// for the history table
	private HistoryTable jksTable;
	// stores the string which needs to be highlighted
	private Map<String, String> cellValueMap;
	// history information object
	private FileHistoryTag historyTag;
	// for inidividual file level data
	private FileTag fileTag;
	// color renderer for highlighting
	private ColorRenderer colorRender;
	// display area for history
	private JPanel historyArea;
	// indicates whether the history data is loaded or not
	private boolean isHisDataLoaded;
	// contains the set of modified rows
	private Set<Integer> modifiedRow;
	// property loader
	private PropertyLoaderUtil propLoader;
	// xml service
	private XMLService xmlService;
	// history fil epath
	private String historyFilePath;
	// xml file name
	private String xmlFileName;
	// html file path
	private String htmlFilePath;
	// add the new row
	private boolean addNewRow;
	// LOGGER for tracking the user activity
	private static final SimpleLogger LOGGER = SimpleLogger.getLogger();
	private Map<String, String> fileNameMap;

	/**
	 * Default constructor
	 */
	public HistoryRenderer() {

	}

	/**
	 * Setter for <tt>htmlFilePath</tt>
	 * 
	 * @param htmlFilePath
	 */
	public void setHtmlFilePath(String htmlFilePath) {
		this.htmlFilePath = htmlFilePath;
	}

	/**
	 * Setter method for <tt>propLoader</tt>
	 * 
	 * @param propLoader
	 */
	public void setPropLoader(PropertyLoaderUtil propLoader) {
		this.propLoader = propLoader;
	}

	/**
	 * Setter method for <tt>xmlService</tt>
	 * 
	 * @param xmlService
	 */
	public void setXMLService(XMLService xmlService) {
		this.xmlService = xmlService;
	}

	/**
	 * Setter method for <tt>xmlFileName</tt>
	 * 
	 * @param xmlFileName
	 */
	public void setXMLFileName(String xmlFileName) {
		this.xmlFileName = xmlFileName;
	}

	/**
	 * For initialization purposes
	 */
	private void init() {
		HistoryModel hisModel = new HistoryModel();
		if (jksTable == null) {
			jksTable = new HistoryTable(hisModel);
		} else {
			jksTable.setModel(hisModel);
		}
		fileNameMap = new HashMap<String, String>();
		addNewRow = false;
		modifiedRow = new HashSet<Integer>();
		isHisDataLoaded = false;
		addColumnNames();
		// to enable the drag effect
		jksTable.setDragEnabled(true);
		// for sorting
		TableModel model = jksTable.getModel();
		RowSorter<TableModel> sorter = new TableRowSorter<TableModel>(model);
		jksTable.setRowSorter(sorter);
		// for the drop effect
		HisTransferHandler dnd = new HisTransferHandler();
		jksTable.setDropMode(DropMode.ON);
		jksTable.setTransferHandler(dnd);
		jksTable.setDragEnabled(true);
		// initialize the color render
		colorRender = new ColorRenderer();
		colorRender.setCellValue(new HashSet<String>());
		jksTable.setDefaultRenderer(String.class, colorRender);
		cellValueMap = new HashMap<String, String>();

		// adding an action listener to the table
		jksTable.addMouseListener(new MouseAdapter() {
			public void mouseClicked(MouseEvent e) {
				if (e.getClickCount() == 1) {
					JTable target = (JTable) e.getSource();
					int row = target.getSelectedRow();
					// int column = target.getSelectedColumn();
					String fileName = (String) jksTable.getModel().getValueAt(
							row, 3);
					if (fileName != null && !StringUtils.isEmpty(fileName)) {
						openFile(fileName);
					}
				}
				if (e.getClickCount() == 2) {
					// System.out.println(" ---------- click 2 ---------");
				}
			}

		});
	}

	/**
	 * Overriding the <code>DefaultTableModel</code> for history table
	 * specific features.
	 * 
	 * @author poornima
	 * 
	 */
	private class HistoryModel extends DefaultTableModel {

		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		/**
		 * Default constructor
		 */
		public HistoryModel() {
			super(ROWS, COLS);
		}

		/**
		 * Override the method to make only last two columns non-editable
		 */
		public boolean isCellEditable(int row, int column) {
			if (column == 3 || column == 4) {
				return false;
			}
			return true;
		}

		/**
		 * Override the method to return relevant return type based on the
		 * column.
		 */
		@SuppressWarnings("unchecked")
		public Class getColumnClass(int column) {
			Class returnValue = Object.class;
			if ((column >= 0) && (column < getColumnCount() - 1)) {
				Object obj = getValueAt(0, column);
				if (obj != null) {
					returnValue = obj.getClass();
				}
			} // else if (column == 0) {
			// returnValue = Boolean.class;
			// }
			return returnValue;
		}

		/**
		 * Override the method to track the rows that are modified during Edit.
		 */
		public void setValueAt(Object value, int row, int column) {
			super.setValueAt(value, row, column);
			if (isHisDataLoaded && column != 0) {
				modifiedRow.add(row);
			}
		}
	}

	/**
	 * Extend the <code>JTable</code> to make history table.
	 * 
	 * @author poornima
	 * 
	 */
	private class HistoryTable extends JTable {

		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		/**
		 * Default constructor.
		 * 
		 * @param dataModel
		 */
		public HistoryTable(TableModel dataModel) {
			super(ROWS, COLS);
			this.setModel(dataModel);
		}
	}

	/**
	 * 
	 * @author poornima
	 * 
	 */
	private class ColorRenderer extends DefaultTableCellRenderer {

		private static final long serialVersionUID = 1L;
		private Set<String> cellValueSet;
		private String searchStr;

		public void setCellValue(Set<String> valueSet) {
			this.cellValueSet = valueSet;
		}

		public Set<String> getCellValue() {
			return this.cellValueSet;
		}

		public void setSearchStr(String searchStr) {
			this.searchStr = searchStr;
		}

		public String getSearchStr() {
			return this.searchStr;
		}

		/*
		 * Overriding the parent method to enable the highlighting of the words
		 * within the history content.
		 */
		public Component getTableCellRendererComponent(JTable table,
				Object value, boolean isSelected, boolean hasFocus, int row,
				int column) {

			if (value instanceof String) {
				setText((String) value);
			}

			if (cellValueSet == null || cellValueSet.isEmpty()) {
				setBackground(Color.WHITE);
				super.getTableCellRendererComponent(table, value, isSelected,
						hasFocus, row, column);
				return this;
			}
			String cellValue = (String) table.getValueAt(row, column);
			if (cellValue != null && cellValue.length() > 0
					&& cellValueSet.contains(cellValue)) {
				setBackground(Color.YELLOW);
			} else {
				setBackground(Color.WHITE);
			}

			// check whether the cell value contains current searchStr
			if (cellValue != null
					&& cellValue.length() > 0
					&& getSearchStr() != null
					&& getSearchStr().length() > 0
					&& cellValue.toLowerCase().indexOf(
							getSearchStr().toLowerCase()) != -1) {
				setBackground(Color.LIGHT_GRAY);
			}

			super.getTableCellRendererComponent(table, value, isSelected,
					hasFocus, row, column);
			return this;
		}
	}

	/**
	 * This method is used to load the history data without the search
	 * component.
	 */
	public Rectangle loadDataOri(Set<String> highlightTxt) {
		Rectangle rect = null;
		// ROWS = getRowCount(historyTag) + 1;
		int tempRowCount = getRowCount(historyTag);
		if (isNewRowRequired()) {
			ROWS = tempRowCount + 1;
		} else {
			ROWS = tempRowCount;
		}
		// set to false to ensure that the rows added are not counted as part of
		// modification/addition to the data
		isHisDataLoaded = false;
		// jksTable.getModel().
		// init();
		HistoryModel hisModel = (HistoryModel) jksTable.getModel();
		hisModel.setRowCount(ROWS);

		if (highlightTxt == null) {
			highlightTxt = new HashSet<String>();
		}

		if (historyTag != null) {
			// boolean isFirstTxtHightd = false;

			List<DateTag> dateTagList = historyTag.getDateTagList();
			if (dateTagList != null && !dateTagList.isEmpty()) {
				int rowCount = 0;
				// set the highlighting text
				colorRender.setCellValue(highlightTxt);
				jksTable.clearSelection();
				// TableModel model = jksTable.getModel();

				for (DateTag dateTg : dateTagList) {
					fileNameMap.put(dateTg.getFileName(), dateTg.getFilePath());
					List<AnnotationTag> annotTagList = dateTg.getAnnotation();
					if (annotTagList != null && !annotTagList.isEmpty()) {
						// iterate the annotation list
						for (int count = 0; count < annotTagList.size(); count++) {
							AnnotationTag annot = annotTagList.get(count);
							cellValueMap.put(annot.getValue(), rowCount + ":"
									+ 1);
							jksTable.setValueAt(annot.getValue(), rowCount, 1);
							cellValueMap
									.put(annot.getKey(), rowCount + ":" + 2);
							// if (highlightTxt.contains(annot.getValue())
							// && !isFirstTxtHightd) {
							// rect = jksTable.getCellRect(rowCount, 0, true);
							// isFirstTxtHightd = true;
							// }
							jksTable.setValueAt(annot.getKey(), rowCount, 2);
							// if (highlightTxt.contains(annot.getKey())
							// && !isFirstTxtHightd) {
							// rect = jksTable.getCellRect(rowCount, 1, true);
							// isFirstTxtHightd = true;
							// }
							jksTable.setValueAt(dateTg.getFileName(), rowCount,
									3);
							jksTable.setValueAt(dateTg.getTimeStamp(),
									rowCount, 4);
							jksTable
									.setValueAt(new Boolean(false), rowCount, 0);
							++rowCount;
						}
					}
					// iterate the notes list
					List<NoteTag> noteList = dateTg.getNote();
					if (noteList != null && !noteList.isEmpty()) {
						for (NoteTag note : noteList) {
							cellValueMap.put(note.getContent(), rowCount + ":"
									+ 1);
							jksTable.setValueAt(note.getContent(), rowCount, 1);
							// if (highlightTxt.contains(note.getContent())
							// && !isFirstTxtHightd) {
							// rect = jksTable.getCellRect(rowCount, 0, true);
							// isFirstTxtHightd = true;
							// }
							jksTable.setValueAt("", rowCount, 2);
							jksTable.setValueAt(dateTg.getFileName(), rowCount,
									3);
							jksTable.setValueAt(dateTg.getTimeStamp(),
									rowCount, 4);
							jksTable
									.setValueAt(new Boolean(false), rowCount, 0);
							++rowCount;
						}
					}
				}
			}
		}
		// add new row if required
		if (isNewRowRequired()) {
			jksTable.setValueAt(null, ROWS - 1, 3);
			jksTable.setValueAt(new Boolean(false), ROWS - 1, 0);
			jksTable.setValueAt(null, ROWS - 1, 1);
			jksTable.setValueAt(null, ROWS - 1, 2);
			jksTable.setValueAt(null, ROWS - 1, 4);
		}
		jksTable.updateUI();
		rect = jksTable.getCellRect(ROWS - 1, 0, true);
		isHisDataLoaded = true;
		return rect;
	}

	private int rowCount = 0;
	private int columnCount = 4;

	/**
	 * Method to clean the table.
	 */
	private void cleanUpTable() {
		// JeksTableModel model = (JeksTableModel) jksTable.getModel();
		// int rows = model.getRowCount();
		// int columns = model.getColumnCount();
		// System.out.println("rows = " + rowCount + ", columns = " +
		// columnCount);

		jksTable.clearSelection();
		// for (int i = 0; i < rowCount + 1; i++) {
		// for (int j = 0; j < columnCount; j++) {
		// jksTable.setValueAt("", i, j);
		// }
		// }
	}

	/**
	 * Method to load the data for the search component.
	 */
	public void loadData(Set<String> highlightTxt, String searchStr) {
		boolean isFiltered = (searchStr != null) && (searchStr.length() > 0);
		// clean the table if it is filtered.
		if (isFiltered)
			cleanUpTable();

		if (highlightTxt == null) {
			highlightTxt = new HashSet<String>();
		}

		isHisDataLoaded = false;
		if (historyTag != null) {
			List<DateTag> dateTagList = historyTag.getDateTagList();
			if (dateTagList != null && !dateTagList.isEmpty()) {
				rowCount = 0;
				colorRender.setCellValue(highlightTxt);
				colorRender.setSearchStr(searchStr);
				jksTable.clearSelection();
				for (DateTag dateTg : dateTagList) {
					// for data with annotation
					List<AnnotationTag> annotTagList = dateTg.getAnnotation();
					if (annotTagList != null && !annotTagList.isEmpty()) {
						for (int count = 0; count < annotTagList.size(); count++) {
							AnnotationTag annot = annotTagList.get(count);
							boolean isAdded = (isFiltered == false);
							/**
							 * || (isFiltered == true && (annot.getValue()
							 * .toLowerCase().indexOf( searchStr.toLowerCase()) !=
							 * -1 || annot .getKey().toLowerCase().indexOf(
							 * searchStr.toLowerCase()) != -1));
							 */
							if (isAdded) {
								cellValueMap.put(annot.getValue(), rowCount
										+ ":" + 1);
								jksTable.setValueAt(annot.getValue(), rowCount,
										1);
								cellValueMap.put(annot.getKey(), rowCount + ":"
										+ 2);

								jksTable
										.setValueAt(annot.getKey(), rowCount, 2);
								jksTable.setValueAt(dateTg.getFileName(),
										rowCount, 3);

								jksTable.setValueAt(dateTg.getTimeStamp(),
										rowCount, 4);

								++rowCount;
							}
						}
					}

					// for data with content
					List<NoteTag> noteList = dateTg.getNote();
					if (noteList != null && !noteList.isEmpty()) {
						for (NoteTag note : noteList) {
							boolean isAdded = (isFiltered == false);
							/**
							 * || (isFiltered == true && (note
							 * .getContent().toLowerCase()
							 * .indexOf(searchStr.toLowerCase()) != -1));
							 */
							if (isAdded) {
								cellValueMap.put(note.getContent(), rowCount
										+ ":" + 1);
								jksTable.setValueAt(note.getContent(),
										rowCount, 1);
								jksTable.setValueAt(dateTg.getFileName(),
										rowCount, 3);
								jksTable.setValueAt(dateTg.getTimeStamp(),
										rowCount, 4);
								++rowCount;
							}
						}
					}
				}
			}
		}
		isHisDataLoaded = true;
		jksTable.updateUI();
		jksTable.scrollRectToVisible(jksTable.getCellRect(0, 0, true));
	}

	/**
	 * Setter method for the <code>FileTag</code>
	 */
	public void setFileTag(FileTag fileTag) {
		this.fileTag = fileTag;
	}

	/**
	 * Setter method for the <code>FileHistoryTag</code>
	 */
	public FileHistoryTag getHistoryTag() {
		return historyTag;
	}

	/**
	 * Setter method for <code>FileHistoryTag</code>
	 */
	public void setHistoryTag(FileHistoryTag historyTag) {
		this.historyTag = historyTag;
	}

	/**
	 * This method will initialize the jks table before returning.
	 */
	public JTable getJeksTable() {
		if (jksTable == null) {
			init();
		}
		return this.jksTable;
	}

	/**
	 * This method will highlight the set of text in the history content. *
	 */
	public Rectangle highlightTextSet(Set<String> cellValues) {
		if (cellValues == null || cellValues.isEmpty()) {
			return null;
		}
		Rectangle rect = null;
		// assign the text pattern to the color renderer
		colorRender.setCellValue(cellValues);
		colorRender.setBackground(Color.white);
		boolean isRectSet = false;
		for (String str : cellValues) {
			// if (cellValueMap.containsKey(str)) {
			String cellParam[] = cellValueMap.get(str).split(":");
			jksTable.setValueAt(str, Integer.parseInt(cellParam[0]), Integer
					.parseInt(cellParam[1]));
			if (!isRectSet) {
				rect = jksTable.getCellRect(Integer.parseInt(cellParam[0]),
						Integer.parseInt(cellParam[1]), true);
			}
		}
		jksTable.updateUI();
		return rect;
	}

	/**
	 * This method will add the history component to the screen.
	 */
	public HistoryRenderer addHistoryComponent(JScrollPane historyScroll,
			SearchBar searchBar) {
		if (historyScroll == null) {
			System.out
					.println("ERROR: the history scroll is not initialized.. ");
			return null;
		}

		// hisTablePanel = new JPanel();
		historyArea = new JPanel();
		// / code for the layout
		historyArea.setLayout(new BorderLayout(10, 20));
		String addRowImg = "";

		addRowImg = this.getClass().getResource(CollabVizConstants.ADD_ROW_IMG)
				.getPath();

		Box boxes[] = new Box[2];
		boxes[0] = Box.createVerticalBox();
		boxes[1] = Box.createHorizontalBox();
		boxes[0].add(getJeksTable().getTableHeader());
		boxes[0].add(getJeksTable());

		JButton addRow = new JButton("Add row");
		// addRow.setIcon(icon);
		addRow.setVisible(true);
		addRow.setEnabled(true);
		addRow.setSize(5, 5);
		addRow.addActionListener(new AddRowActionListener());

		JButton delete = new JButton("Delete");
		delete.setVisible(true);
		delete.setEnabled(true);
		delete.addActionListener(new DeleteActionListener());

		JButton save = new JButton("Save");
		save.setVisible(true);
		save.setEnabled(true);
		save.addActionListener(new SaveActionListener());

		JButton cancel = new JButton("Cancel");
		cancel.setVisible(true);
		cancel.setEnabled(true);
		cancel.addActionListener(new CancelActionListener());

		boxes[1].add(Box.createHorizontalGlue());
		// add row button
		boxes[1].add(addRow);
		boxes[1].add(Box.createRigidArea(new Dimension(5, 5)));
		// delete button
		boxes[1].add(delete);
		boxes[1].add(Box.createRigidArea(new Dimension(5, 5)));
		// save button
		boxes[1].add(save);
		boxes[1].add(Box.createRigidArea(new Dimension(5, 5)));
		// cancel button
		boxes[1].add(cancel);
		boxes[1].add(Box.createRigidArea(new Dimension(100, 5)));
		// search bar
		boxes[1].add(searchBar);
		boxes[1].add(Box.createRigidArea(new Dimension(350, 5)));
		historyScroll.setViewportView(historyArea);
		historyArea.add(boxes[0], BorderLayout.NORTH);
		historyArea.add(boxes[1], BorderLayout.SOUTH);
		return this;
	}

	/**
	 * Sets the history area as viewport.
	 */
	public void setViewportViewForHistory(JScrollPane historyScroll) {
		if (historyScroll == null) {
			System.out.println("ERROR: the history scroll is not initialized");
			return;
		}
		historyScroll.setViewportView(historyArea);
	}

	/**
	 * Method to scroll to bottom.
	 */
	public void scrollToBotton(Rectangle rect) {
		if (rect != null) {
			historyArea.scrollRectToVisible(rect);
		}
	}

	/**
	 * Fetch the row count for the given <code>FileHistoryTag</code>.
	 */
	private int getRowCount(FileHistoryTag historyTag) {
		if (historyTag == null) {
			return 0;
		}
		int result = 0;
		List<DateTag> dtList = historyTag.getDateTagList();
		if (dtList == null || dtList.isEmpty()) {
			return result;
		}
		for (DateTag date : dtList) {
			List<AnnotationTag> annoList = date.getAnnotation();
			if (annoList != null && !annoList.isEmpty()) {
				result += annoList.size();
			}
			List<NoteTag> noteList = date.getNote();
			if (noteList != null && !noteList.isEmpty()) {
				result += noteList.size();
			}
		}
		return result;
	}

	/**
	 * This class is an extension of the <code>TransferHandler</code>.
	 * 
	 * @author poornima
	 * 
	 */
	private class HisTransferHandler extends TransferHandler {
		public boolean canImport(TransferHandler.TransferSupport support) {
			if (!support.isDataFlavorSupported(DataFlavor.stringFlavor)) {
				return false;
			}
			JTable.DropLocation dl = (JTable.DropLocation) support
					.getDropLocation();
			try {
				String data = (String) support.getTransferable()
						.getTransferData(DataFlavor.stringFlavor);
				if (data != null && !StringUtils.isEmpty(data)) {
					return true;
				}
			} catch (Exception e) {
				return false;
			}
			return false;
		}

		public boolean importData(TransferHandler.TransferSupport support) {
			if (!canImport(support)) {
				return false;
			}
			Transferable transferable = support.getTransferable();
			String data;
			try {
				data = (String) transferable
						.getTransferData(DataFlavor.stringFlavor);
				JTable.DropLocation dl = (JTable.DropLocation) support
						.getDropLocation();
				int column = dl.getColumn();
				int row = dl.getRow();
				if (data != null & !StringUtils.isEmpty(data)) {
					// set the dragged text in the corresponding column, row...
					jksTable.getModel().setValueAt(data, row, column);
				}
			} catch (Exception e) {
				return false;
			}
			return false;
		}
	}

	/**
	 * Method to add the column names.
	 */
	private void addColumnNames() {
		if (jksTable == null) {
			System.out
					.println("ERROR: table not initialized, column names cannot be added.");
			return;
		}
		TableColumnModel columnModel = jksTable.getTableHeader()
				.getColumnModel();
		columnModel.getColumn(1).setHeaderValue("User entered data");
		columnModel.getColumn(1).setPreferredWidth(180);
		columnModel.getColumn(2).setHeaderValue("Data from document");
		columnModel.getColumn(2).setPreferredWidth(180);
		columnModel.getColumn(3).setHeaderValue("File name");
		columnModel.getColumn(3).setPreferredWidth(80);
		columnModel.getColumn(4).setHeaderValue("Timestamp");
		columnModel.getColumn(0).setHeaderValue("Select for delete");
		columnModel.getColumn(0).setPreferredWidth(10);
	}

	/**
	 * Adding the action listener for Add Row button.
	 * 
	 * @author poornima
	 * 
	 */
	private class AddRowActionListener implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent e) {
			LOGGER.log(Location.NH, "add row button clicked");
			addNewRow = true;
			loadDataOri(colorRender.getCellValue());
		}

	}

	private boolean isNewRowRequired() {
		return addNewRow;
	}

	/**
	 * Implement the ActionListener for Delete operation.
	 * 
	 * @author poornima
	 * 
	 */
	private class DeleteActionListener implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent e) {
			LOGGER.log(Location.NH, "delete row button clicked");
			// System.out.println("------------- DELETE in action listener ");
			// System.out.println("------------- Before Delete ------------- ");
			// displayHistory();
			// System.out.println("------------- Before Delete ------------- ");
			StringBuffer errorList = new StringBuffer();
			boolean isModifdAddRowFlg = false;
			// timestamp mapped to annot/notes
			HashMap<String, String> deleteData = new HashMap<String, String>();
			StringBuffer valueData = new StringBuffer("");
			for (int count = 0; count <= ROWS - 1; count++) {
				System.out.println("---- count : " + count);
				boolean boolVal = (Boolean) jksTable.getValueAt(count, 0);
				if (boolVal) {
					String timeStamp = (String) jksTable.getValueAt(count, 4);
					String docData = (String) jksTable.getValueAt(count, 2);
					String userData = (String) jksTable.getValueAt(count, 1);
					String fileName = (String) jksTable.getValueAt(count, 3);
					// validation of data
					if ((docData == null || StringUtils.isEmpty(docData))
							&& (userData == null || StringUtils
									.isEmpty(userData))) {
						// both the user data and the doc data are empty,
						// add to error list.
						// errorList
						// .append("Please select a valid row with user
						// data/document data for deletion.");
						addNewRow = false;
						isModifdAddRowFlg = true;
						continue;
					} else if ((docData != null && !StringUtils
							.isEmpty(docData))
							&& (userData == null || StringUtils
									.isEmpty(userData))) {
						errorList
								.append("Please add user data to the the text: "
										+ docData);
						continue;
					}
					if (deleteData.containsKey(timeStamp)) {
						if (docData != null
								&& !StringUtils.isEmpty(docData.trim())
								&& userData != null
								&& !StringUtils.isEmpty(userData.trim())) {
							// this is annotation
							valueData = new StringBuffer(deleteData
									.get(timeStamp));
							valueData.append("_");
							valueData.append(docData.trim());
							valueData.append(":");
							valueData.append(userData.trim());
							valueData.append(":");
							valueData.append(fileName.trim());
							deleteData.put(timeStamp, valueData.toString());
						} else if (userData != null
								&& !StringUtils.isEmpty(userData.trim())
								&& (docData == null || StringUtils
										.isEmpty(docData))) {
							// this is notes
							valueData = new StringBuffer(deleteData
									.get(timeStamp));
							valueData.append("_");
							valueData.append(userData.trim());
							valueData.append(":");
							valueData.append(fileName.trim());
							deleteData.put(timeStamp, valueData.toString());
						}
					} else {
						// first time entry
						if (docData != null
								&& !StringUtils.isEmpty(docData.trim())
								&& userData != null
								&& !StringUtils.isEmpty(userData.trim())) {
							// this is annotation
							deleteData.put(timeStamp, docData + ":" + userData
									+ ":" + fileName);

						} else if (userData != null
								&& !StringUtils.isEmpty(userData.trim())
								&& (docData == null || StringUtils
										.isEmpty(docData))) {
							// this is notes
							deleteData
									.put(timeStamp, userData + ":" + fileName);
						}
					}
				}
			}

			if (deleteData.isEmpty() && !isModifdAddRowFlg) {
				errorList.append("Please select a row for deletion.");
			}
			if (deleteData.isEmpty() && isModifdAddRowFlg
					&& errorList.length() <= 0) {
				loadDataOri(colorRender.getCellValue());
				return;
			}
			if (errorList.length() > 0) {
				JOptionPane.showMessageDialog(null, errorList.toString(),
						"Error", JOptionPane.ERROR_MESSAGE);
				return;
			}

			List<DateTag> dateList = historyTag.getDateTagList();
			List<DateTag> modifiedDateList = new ArrayList<DateTag>();
			if (dateList != null && !dateList.isEmpty()) {
				Set<String> timeStamp = deleteData.keySet();
				Map<String, List<AnnotationTag>> deleteAnnot = new HashMap<String, List<AnnotationTag>>();
				Map<String, List<NoteTag>> deleteNote = new HashMap<String, List<NoteTag>>();
				for (DateTag dt : dateList) {
					if (!timeStamp.contains(dt.getTimeStamp())) {
						modifiedDateList.add(dt);
						continue;
					}

					String dtValues[] = deleteData.get(dt.getTimeStamp())
							.split("_");
					Set<String> dtValSet = new HashSet<String>(Arrays
							.asList(dtValues));
					List<AnnotationTag> annoList = dt.getAnnotation();
					StringBuffer annoBuf = new StringBuffer("");

					if (annoList != null && !annoList.isEmpty()) {
						List<AnnotationTag> modifiedAnnotTagList = new ArrayList<AnnotationTag>();
						for (AnnotationTag annot : annoList) {
							annoBuf = new StringBuffer("");
							annoBuf.append(annot.getKey());
							annoBuf.append(":");
							annoBuf.append(annot.getValue());
							annoBuf.append(":");
							annoBuf.append(dt.getFileName());
							if (dtValSet.contains(annoBuf.toString())) {
								if (deleteAnnot.get(dt.getFileName()) == null
										|| deleteAnnot.get(dt.getFileName())
												.isEmpty()) {
									deleteAnnot.put(dt.getFileName(),
											new ArrayList<AnnotationTag>());
								}
								List<AnnotationTag> annotlist = deleteAnnot
										.get(dt.getFileName());
								annotlist.add(annot);
								deleteAnnot.put(dt.getFileName(), annotlist);
								continue;
							}
							modifiedAnnotTagList.add(annot);
						}
						dt.setAnnotation(modifiedAnnotTagList);
					}
					List<NoteTag> noteList = dt.getNote();
					if (noteList != null && !noteList.isEmpty()) {
						List<NoteTag> modifiedNoList = new ArrayList<NoteTag>();
						for (NoteTag note : noteList) {
							annoBuf = new StringBuffer("");
							annoBuf.append(note.getContent());
							annoBuf.append(":");
							annoBuf.append(dt.getFileName());
							if (dtValSet.contains(annoBuf.toString())) {
								if (deleteNote.get(dt.getFileName()) == null
										|| deleteNote.get(dt.getFileName())
												.isEmpty()) {
									deleteNote.put(dt.getFileName(),
											new ArrayList<NoteTag>());
								}
								List<NoteTag> list = deleteNote.get(dt
										.getFileName());
								list.add(note);
								deleteNote.put(dt.getFileName(), list);
								continue;
							}
							modifiedNoList.add(note);
						}
						dt.setNote(modifiedNoList);
					}
					if ((dt.getAnnotation() != null && !dt.getAnnotation()
							.isEmpty())
							|| (dt.getNote() != null && !dt.getNote().isEmpty())) {
						modifiedDateList.add(dt);
					}
				}
				// save the modified history tag in the xml
				historyTag.setDateTagList(modifiedDateList);
				saveHistory();
				deleteDataFromFile(deleteAnnot, deleteNote);
				JOptionPane.showMessageDialog(null,
						"Selected records are deleted successfully", "Message",
						JOptionPane.PLAIN_MESSAGE);
				loadDataOri(colorRender.getCellValue());
				// System.out.println("------------- After Delete -------------
				// ");
				// displayHistory();
				// System.out.println("------------- After Delete -------------
				// ");
			}
		}
	}

	/**
	 * Method deletes the data from the history and corresponding file name.
	 */
	private void deleteDataFromFile(Map<String, List<AnnotationTag>> annotMap,
			Map<String, List<NoteTag>> noteMap) {
		if ((annotMap == null || annotMap.isEmpty())
				&& (noteMap == null || noteMap.isEmpty())) {
			return;
		}
		String htmlFileName = new File(htmlFilePath).getName();
		// delete the annotations first
		for (Map.Entry<String, List<AnnotationTag>> aMap : annotMap.entrySet()) {
			String fileName = aMap.getKey();
			if (fileName.equals(htmlFileName)) {
				// from the current file
				List<AnnotationTag> modifiedList = new ArrayList<AnnotationTag>();
				for (AnnotationTag annoTag : aMap.getValue()) {
					for (AnnotationTag aTag : fileTag.getAnnotation()) {
						if (annoTag.getKey().equals(aTag.getKey())
								&& annoTag.getValue().equals(aTag.getValue())) {
							continue;
						}
						modifiedList.add(annoTag);
					}
				}
				// check if there are notes to be deleted...
				List<NoteTag> modifiedNoteList = new ArrayList<NoteTag>();
				if (noteMap.containsKey(aMap.getKey())) {
					for (NoteTag noteTag : noteMap.get(aMap.getKey())) {
						for (NoteTag nTag : fileTag.getNote()) {
							if (nTag.getContent().equals(noteTag.getContent())) {
								continue;
							}
							modifiedNoteList.add(nTag);
						}
					}
				}
				fileTag.setNote(modifiedNoteList);
				fileTag.setAnnotation(modifiedList);
				saveFileTag(xmlFileName, fileTag);
				continue;
			}

			// from a different file
			String xmlFileName = getXmlFileName(aMap.getKey());
			try {
				FileTag otherFileTag = (FileTag) xmlService
						.unmarshall(xmlFileName);
				List<AnnotationTag> modifiedList = new ArrayList<AnnotationTag>();
				for (AnnotationTag annoTag : aMap.getValue()) {
					for (AnnotationTag aTag : otherFileTag.getAnnotation()) {
						if (annoTag.getKey().equals(aTag.getKey())
								&& annoTag.getValue().equals(aTag.getValue())) {
							continue;
						}
						modifiedList.add(annoTag);
					}
				}
				// check if there are notes to be deleted...
				List<NoteTag> modifiedNoteList = new ArrayList<NoteTag>();
				if (noteMap.containsKey(aMap.getKey())) {
					for (NoteTag noteTag : noteMap.get(aMap.getKey())) {
						for (NoteTag nTag : otherFileTag.getNote()) {
							if (nTag.getContent().equals(noteTag.getContent())) {
								continue;
							}
							modifiedNoteList.add(nTag);
						}
					}
				}
				otherFileTag.setNote(modifiedNoteList);
				otherFileTag.setAnnotation(modifiedList);
				saveFileTag(xmlFileName, otherFileTag);
			} catch (CollabVizException exp) {
				System.out
						.println("ERROR: error while deleting the data from file : "
								+ aMap.getKey());
				exp.printStackTrace();
			}
		}
		// this section if there are only notes to be deleted...
		for (Map.Entry<String, List<NoteTag>> entry : noteMap.entrySet()) {
			String fileName = entry.getKey();
			if (fileName.equals(htmlFileName)) {
				// from the current file
				List<NoteTag> modifiedList = new ArrayList<NoteTag>();
				for (NoteTag noteTag : entry.getValue()) {
					for (NoteTag nTag : fileTag.getNote()) {
						if (noteTag.getContent().equals(nTag.getContent())) {
							continue;
						}
						modifiedList.add(nTag);
					}
				}
				fileTag.setNote(modifiedList);
				saveFileTag(xmlFileName, fileTag);
				continue;
			}
			// from a different file
			String xmlFileName = getXmlFileName(entry.getKey());
			try {
				FileTag otherFileTag = (FileTag) xmlService
						.unmarshall(xmlFileName);
				List<NoteTag> modifiedList = new ArrayList<NoteTag>();
				for (NoteTag noteTag : entry.getValue()) {
					for (NoteTag nTag : otherFileTag.getNote()) {
						if (noteTag.getContent().equals(nTag.getContent())) {
							continue;
						}
						modifiedList.add(noteTag);
					}
				}
				otherFileTag.setNote(modifiedList);
				saveFileTag(xmlFileName, otherFileTag);
			} catch (Throwable th) {
				System.out.println("ERROR: error while parsing the xml file: "
						+ entry.getKey());
				th.printStackTrace();
			}
		}
	}

	/** ***************DEBUG****************** */
	private void displayHistory() {
		if (historyTag != null) {
			if (historyTag.getDateTagList() == null
					|| historyTag.getDateTagList().isEmpty()) {
				System.out
						.println(" ------ ERROR no date list in the memory --------- ");
				return;
			}
			for (DateTag dt : historyTag.getDateTagList()) {
				System.out.println("--------------- DATE ---------------");
				System.out.println("------ ANNOTATIONS-----");
				if (dt.getAnnotation() != null && !dt.getAnnotation().isEmpty()) {

					for (AnnotationTag annot : dt.getAnnotation()) {
						System.out.println("------ key: " + annot.getKey()
								+ ":" + annot.getValue() + "  filename:"
								+ dt.getFileName() + " timestamp: "
								+ dt.getTimeStamp());
					}
				}

				if (dt.getNote() != null && !dt.getNote().isEmpty()) {
					System.out.println("------ NOTES -----");
					for (NoteTag note : dt.getNote()) {
						System.out.println("------ content: "
								+ note.getContent() + "  filename:"
								+ dt.getFileName() + " timestamp: "
								+ dt.getTimeStamp());
					}
				}
				System.out.println("--------------- DATE ---------------");
			}

		}
	}

	/** ***************DEBUG****************** */

	/**
	 * Implement the ActionListener for Save.
	 * 
	 * @author poornima
	 * 
	 */
	private class SaveActionListener implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent e) {

			LOGGER.log(Location.NH, "save row button clicked");

			StringBuffer errorList = new StringBuffer("");
			String timeStamp = new Date().toString();
			DateTag dateTag = new DateTag();
			String htmlFileName = new File(htmlFilePath).getName();
			System.out
					.println("------------- SAVE in action listener html file : "
							+ htmlFileName + " file path:" + htmlFilePath);
			// System.out
			// .println("-------------------------- BEFORE SAVING
			// -----------------------------");
			// displayHistory();
			// System.out
			// .println("-------------------------- BEFORE SAVING
			// -----------------------------");

			dateTag.setFileName(htmlFileName);
			dateTag.setTimeStamp(timeStamp);
			dateTag.setAnnotation(new ArrayList<AnnotationTag>());
			dateTag.setNote(new ArrayList<NoteTag>());
			dateTag.setFilePath(htmlFilePath);
			boolean isEntryAdded = false;
			if (fileTag.getAnnotation() == null) {
				fileTag.setAnnotation(new ArrayList<AnnotationTag>());
			}
			if (fileTag.getNote() == null) {
				fileTag.setNote(new ArrayList<NoteTag>());
			}

			// check if there is new entry
			String userData = (String) jksTable.getModel().getValueAt(ROWS - 1,
					1);
			String docData = (String) jksTable.getModel().getValueAt(ROWS - 1,
					2);
			if ((docData == null || StringUtils.isEmpty(docData))
					&& (userData == null || StringUtils.isEmpty(userData))
					&& (modifiedRow == null || modifiedRow.isEmpty())) {
				errorList
						.append("Please make modifications or add a new entry before saving.");
				JOptionPane.showMessageDialog(null, errorList.toString(),
						"Error", JOptionPane.ERROR_MESSAGE);
				return;
			}
			if ((docData != null && !StringUtils.isEmpty(docData))
					&& (userData == null || StringUtils.isEmpty(userData))) {
				// this is an annotation entry without the doc data, show error
				errorList
						.append("Please enter the user data for the document data: "
								+ docData);
				JOptionPane.showMessageDialog(null, errorList.toString(),
						"Error", JOptionPane.ERROR_MESSAGE);
				return;
			} else if ((docData != null && !StringUtils.isEmpty(docData))
					&& (userData != null && !StringUtils.isEmpty(userData))) {
				// this is an annotation save it
				AnnotationTag annot = new AnnotationTag();
				annot.setKey(docData);
				annot.setValue(userData);
				annot.setTimeStamp(timeStamp);
				dateTag.getAnnotation().add(annot);
				fileTag.getAnnotation().add(annot);
				isEntryAdded = true;
				modifiedRow.remove(ROWS - 1);
				colorRender.getCellValue().add(annot.getKey());
				colorRender.getCellValue().add(annot.getValue());
			} else if ((docData == null || StringUtils.isEmpty(docData))
					&& (userData != null && !StringUtils.isEmpty(userData))) {
				// this is a note..
				NoteTag note = new NoteTag();
				note.setContent(userData);
				note.setTimeStamp(timeStamp);
				dateTag.getNote().add(note);
				fileTag.getNote().add(note);
				isEntryAdded = true;
				modifiedRow.remove(ROWS - 1);
				colorRender.getCellValue().add(note.getContent());
			}
			// check if there is a modification..
			if (modifiedRow != null && !modifiedRow.isEmpty()) {
				for (int row : modifiedRow) {
					String usrDt = (String) jksTable.getModel().getValueAt(row,
							1);
					String docDt = (String) jksTable.getModel().getValueAt(row,
							2);
					String fileName = (String) jksTable.getModel().getValueAt(
							row, 3);
					if ((docDt == null || StringUtils.isEmpty(docDt)
							&& (usrDt != null && !StringUtils.isEmpty(usrDt)))) {
						// this is a note..
						NoteTag note = new NoteTag();
						note.setContent(usrDt);
						note.setTimeStamp(timeStamp);
						if (!htmlFileName.equals(fileName)) {
							// this is a modified note from a different file
							String xmlFileName = getXmlFileName(fileName);
							if (xmlFileName != null
									&& !StringUtils.isEmpty(xmlFileName)) {
								try {
									FileTag otherFile = (FileTag) xmlService
											.unmarshall(xmlFileName);
									if (otherFile.getNote() == null) {
										otherFile
												.setNote(new ArrayList<NoteTag>());
									}
									otherFile.getNote().add(note);
									saveFileTag(xmlFileName, otherFile);
									dateTag.setFileName(fileName);
								} catch (CollabVizException exp) {
									exp.printStackTrace();
								}
							}

						} else {
							// save the note for current file
							fileTag.getNote().add(note);
							colorRender.getCellValue().add(note.getContent());
						}
						dateTag.getNote().add(note);
						isEntryAdded = true;
					}
					if ((docDt != null && !StringUtils.isEmpty(docDt) && (usrDt != null && !StringUtils
							.isEmpty(usrDt)))) {
						// this is annotation
						AnnotationTag annot = new AnnotationTag();
						annot.setKey(docDt);
						annot.setValue(usrDt);
						annot.setTimeStamp(timeStamp);
						if (!htmlFileName.equals(fileName)) {
							System.out
									.println("---------- the HTML file name differ : ");
							// save the annotation in another file
							String xmlFileName = getXmlFileName(fileName);
							if (xmlFileName != null
									&& !StringUtils.isEmpty(xmlFileName)) {
								try {
									FileTag otherFile = (FileTag) xmlService
											.unmarshall(xmlFileName);
									if (!isDocDataModified(otherFile, docDt)) {
										// the annotated data is not modified,
										// so save the data against the previoue
										// file
										if (otherFile.getAnnotation() == null) {
											otherFile
													.setAnnotation(new ArrayList<AnnotationTag>());
										}
										otherFile.getAnnotation().add(annot);
										saveFileTag(xmlFileName, otherFile);
										dateTag.setFileName(fileName);
									} else {
										// the annotated data is modified,
										// so save the annotation wrt to the
										// current file
										fileTag.getAnnotation().add(annot);
										colorRender.getCellValue().add(
												annot.getKey());
										colorRender.getCellValue().add(
												annot.getValue());
									}
								} catch (CollabVizException exp) {
									exp.printStackTrace();
								}
							}
						} else {
							// save the note for current file
							fileTag.getAnnotation().add(annot);
							colorRender.getCellValue().add(annot.getKey());
							colorRender.getCellValue().add(annot.getValue());
						}
						dateTag.getAnnotation().add(annot);
						isEntryAdded = true;
					}
				}
			}
			if (isEntryAdded) {
				// entries added save the history and file obj
				if (historyTag.getDateTagList() == null) {
					historyTag.setDateTagList(new ArrayList<DateTag>());
				}
				historyTag.getDateTagList().add(dateTag);
				// save the file tag
				saveFileTag(xmlFileName, fileTag);
				// save the history
				saveHistory();
				// propagate file tag and history tag
				AllComponents.setFileTag(fileTag);
				AllComponents.setHistoryTag(historyTag);
				JOptionPane.showMessageDialog(null,
						"The data is saved successfully.", "Message",
						JOptionPane.PLAIN_MESSAGE);
				// load the history data again after saving
				loadDataOri(colorRender.getCellValue());
				// highlight the annotations on the document
				AllComponents.highlightAnnotations(fileTag.getAnnotation());
				modifiedRow = new HashSet<Integer>();

				// System.out
				// .println("-------------------------- AFTER SAVING
				// ----------------------------");
				// displayHistory();
				// System.out
				// .println("-------------------------- AFTER SAVING
				// ----------------------------");
			}
		}
	}

	/**
	 * This method checks if the doc data was modified or not. It is checked
	 * with the key value in the annotation.
	 * 
	 * @returns <true> if the document data was modified, else returns <false>.
	 */
	private boolean isDocDataModified(FileTag fileTag, String docData) {
		if (docData == null || StringUtils.isEmpty(docData) || fileTag == null) {
			System.out
					.println("ERROR: incoming doc data for the given file is empty.");
			return false;
		}
		List<AnnotationTag> annotationList = fileTag.getAnnotation();
		for (AnnotationTag annot : annotationList) {
			if (annot.getKey().equals(docData.trim())) {
				return false;
			}
		}
		return true;
	}

	/**
	 * Implement the ActionListener for Cancel.
	 * 
	 * @author poornima
	 * 
	 */
	private class CancelActionListener implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent e) {
			LOGGER.log(Location.NH, "cancel button clicked");
			loadDataOri(colorRender.getCellValue());
		}
	}

	/**
	 * Method to save the history in the xml file.
	 */
	private void saveHistory() {
		try {
			if (historyFilePath == null || StringUtils.isEmpty(historyFilePath)) {
				StringBuffer historyFile = new StringBuffer(propLoader
						.getProp(CollabVizConstants.XML_FILES_FOLDER_PATH));
				historyFile.append(CollabVizConstants.FILE_DELIMITER);
				historyFile.append(CollabVizConstants.HISTORY_FILE_NAME);
				historyFilePath = historyFile.toString();
			}
			xmlService.marshall(historyFilePath, historyTag);
		} catch (Throwable e) {
			System.out.println("ERROR: error while saving the history.");
			e.printStackTrace();
		}
	}

	/**
	 * Method to save the file tag data in corresponding xml file.
	 */
	private void saveFileTag(String filePath, FileTag fileTag) {
		try {
			if (filePath == null || StringUtils.isEmpty(filePath)) {
				System.out
						.println("ERROR: error while saving the file tag.. set the file tag before saving");
				return;
			}
			xmlService.marshall(filePath, fileTag);
		} catch (Throwable th) {
			System.out.println("ERROR: error while saving the file.");
			th.printStackTrace();
		}
	}

	/**
	 * Method to fetch the xml file name for the given html file name.
	 */
	private String getXmlFileName(String htmlFileName) {
		if (htmlFileName == null || StringUtils.isEmpty(htmlFileName)) {
			System.out
					.println("ERROR: error while generating the xml file name...");
			return null;
		}
		StringBuffer xmlFileName = new StringBuffer("");
		try {
			// load the HTML file path
			StringBuffer htmlFilePath = new StringBuffer(propLoader
					.getProp(CollabVizConstants.HTML_FILES_FOLDER));
			htmlFilePath.append(CollabVizConstants.FILE_DELIMITER);
			htmlFilePath.append(htmlFileName);
			List<String> xmlFileList = AllComponents
					.listXmlFilesForHtml(htmlFilePath.toString());
			int xmlFileListSize = xmlFileList.size();
			if (xmlFileList != null && !xmlFileList.isEmpty()) {
				xmlFileName.append(PropertyLoaderUtil
						.getProp(CollabVizConstants.XML_FILES_FOLDER_PATH));
				xmlFileName.append(CollabVizConstants.FILE_DELIMITER);
				xmlFileName.append(htmlFileName
						.split(CollabVizConstants.DOT_REGEX)[0]);
				xmlFileName.append(CollabVizConstants.FILE_DELIMITER);
				xmlFileName.append(xmlFileList.get(xmlFileListSize - 1));
			}

		} catch (Throwable th) {
			System.out
					.println("ERROR: error while returning the xml file name");
			th.printStackTrace();
		}
		return xmlFileName.toString();
	}

	/**
	 * This method is used to open the corresponding HTML file when you click
	 * the corresponding row in the history.
	 */
	private void openFile(String fileName) {
		String filePath = (String) fileNameMap.get(fileName).replace('/', '\\');
		AllComponents.saveCurrentPath(filePath);
		FileTree tree = AllComponents.getFileTree();

		tree.expandTreeByPath(filePath, true);
	}
}
